#pragma once
#include <array>
#include <optional>
#include <string_view>

// 为了演示方便,我们直接把enum相关的变量模版的主模版放在文件里
// 更好的办法单独建一个文件,这部分代码接口借鉴了magic_enum
namespace simple_enum {
namespace enum_details {
// enum类型中元素名字的数组变量主模版
// 这里只声明不定义
template <typename E> inline constexpr bool names_v;

// enum类型中元素数值的数组变量主模版
template <typename E> inline constexpr bool values_v;
// enum类型中(元素名，数值）的数组变量主模版
template <typename E> inline constexpr bool entries_v;
} // namespace enum_details

// enum value to string
// 如果不存在，返回空
template <typename EnumType>
constexpr auto enum_name(EnumType value) noexcept -> std::string_view {
  using D = std::decay_t<EnumType>;
  for (const auto [name, val] : enum_details::entries_v<D>) {
    if (val == static_cast<std::underlying_type_t<D>>(value)) {
      return name;
    }
  }
  // 这个路径应该不会发生
  return {};
}

// string to enum value
template <typename EnumType>
constexpr std::optional<EnumType> enum_cast(std::string_view str) {
  for (const auto [name, val] : enum_details::entries_v<EnumType>) {
    if (name == str) {
      return static_cast<EnumType>(val);
    }
  }
  return {};
}
} // namespace simple_enum